/*
    多态测试类
      多态实现的前提条件：
        1.必须存在继承或者实现关系
        2.子类必须重写父类的**所有**成员方法(包括非抽象的方法)
        3.父类对象 引用指向 子类对象 -> 将子类对象赋值给父类对象 -> 语法: 父类名 对象名 = new 子类名();
          向上造型（相当于自动类型转换） ： 小 -> 大 （大类型 = 小类型）
          向下转型（相当于强制类型转换） ： 大 -> 小 （小类型 = 大类型）
          内容回顾：编译时 / 运行时
            xx.java -> 编译 -> xx.class -> 类加载 -> jvm运行
            编译时类型 = 运行时类型
              编译时类型:决定最终能调用什么变量和方法 -> 检查等号前的类型是否具有父子类关系
              运行时类型:决定最终调用的方法是什么 -> 检查子类是否重写所有方法
              总结：编译时看左边，运行时看右边
 */
public class TestDemo {
    public static void main(String[] args) {
        // Zi1 zi1 = new zi1();不叫多态

        //多态写法

        /*
         2.父类对象 引用指向 子类对象
           向上造型
           编译时类型 = 运行时类型
              编译时类型:决定最终能调用什么变量和方法 -> 检查等号前的类型是否具有父子类关系
              运行时类型:决定最终调用的方法是什么 -> 检查子类是否重写所有方法
              总结：编译时看左边，运行时看右边
         */
        //3.Zi1重写了父类中所有的方法
        Fu zi1 = new Zi1();
        //3.Zi2没重写父类中所有的方法
        Fu zi2 = new Zi2();
        //测试运行结果
        zi1.eat();
        zi2.eat();
        //以上存在问题，无法调用子类的成员方法！
        //zi1.phone无法调用，编译报错
        //用以下方法调用成员变量 - 向下转型 （强制类型转换）
        Zi1 z1 = (Zi1) zi1;
        System.out.println("成员变量为："+z1.phone);
        z1.eat();
        z1.play();
        //存在问题：所有类型是否都能强转？
        //ClassCastException : 类型转换异常
        /*
         编译时：认为zi1是Fu类，编译不报错
         运行时：发现zi1不是zi2类，允许抛出ClassCastException异常
         Zi2 z2 = (Zi2) zi1; -> 编译不报错，运行时会抛出ClassCastException异常
         z2.play();
         */
        //解决办法：利用instanceof判断转换前后是否是需要转换的类型 ,如下代码块
        Fu zi3 = new Zi2();
        if (zi3 instanceof Zi1){
            //...
        } else if (zi3 instanceof Zi2) {
            //...
            Zi2 z3 = (Zi2) zi3;
            z3.eat(); //  -> 因为没重写所有父类方法，强转会出现类似精度丢失的问题，调用父类eat方法
            z3.play();
        }
    }
}